package com.rem.rabbitmq.ee.Cack;

import com.rabbitmq.client.Channel;
import com.rem.rabbitmq.ee.RabbitMqUtils;

import java.util.Scanner;


/**
 * 消费者完成一个任务可能需要一段时间，如果其中一个消费者处理一个长的任务并仅只完成了部分突然它挂掉了，会发生什么情况。
 * RabbitMQ一旦向消费者传递了一条消息，便立即将该消息标记为删除。
 * 在这种情况下，突然有个消费者挂掉了，我们将丢失正在处理的消息。以及后续发送给该消费这的消息，因为它无法接收到。
 * 为了保证消息在发送过程中不丢失，rabbitmq引入消息应答机制，
 * 消息应答就是:消费者在接收到消息并且处理该消息之后，告诉rabbitmq它已经处理了，rabbitmq可以把该消息删除了。
 * <p>
 * <p>
 * 消息应答类型:
 * 1) 手动应答
 * ********消费者处理完业务逻辑，手动返回ack（通知）告诉队列处理完了，队列进而删除消息。
 * 2) 自动应答
 * ********不在乎消费者对消息处理是否成功，都会告诉队列删除消息。如果处理消息失败，实现自动补偿（队列投递过去 重新处理）
 * 这种模式需要在高吞吐量和数据传输安全性方面做权衡,
 * ** a.channel或者连接关闭 消息会丢失
 * ** b. 消息过载，并且对消息数量没有限制(或者消费者来不及处理) 消息积压，导致内存耗尽 消费者内存被系统杀死
 * 所以这种模式仅适用在消费者可以高效并以某种速率能够处理这些消息的情况下使用
 * <p>
 * <p>
 * 消息应答类型方式:
 * A.Channel.basicAck(用于肯定确认)         RabbitMQ已知道该消息并且成功的处理消息，可以将其丢弃了
 * B.Channel.basicNack(用于否定确认)
 * C.Channel.basicReject(用于否定确认) 与Channel.basicNack相比少一个参数,不处理该消息了直接拒绝，可以将其丢弃了
 * <p>
 * <p>
 * Multiple: 批量处理
 * true代表批量应答channel上未应答的消息  包含还未应答的消息都会被确认收到应答消息
 * false 会应答当前tag的消息  之前的消息不会应答
 * <p>
 * <p>
 * 消息自动重新入队
 * 如果消费者由于某些原因失去连接(其通道已关闭，连接已关闭或TCP连接丢失)，导致消息未发送ACK确认，
 * RabbitMQ将了解到消息未完全处理，并将对其重新排队。如果此时其他消费者可以处理，它将很快将其重新分发给另一个消费者。这样，即使某个消费者偶尔死亡，也可以确保不会丢失任何消息。
 * <p>
 * 轮训消费消息时，即使其中有消费者在等待，也会均匀消费  当关闭其中一个消费者时会将为消费的消息转给另外一个消费者
 * <p>
 * <p>
 *
 * @author Rem
 * @date 2021-12-23
 */

public class AckProducer {

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        //声明队列
        channel.queueDeclare(RabbitMqUtils.QUEUE_ACK, false, false, false, null);

        System.err.println("开始发送消息...");
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String message = scanner.next();

            //发送消息
            channel.basicPublish("", RabbitMqUtils.QUEUE_ACK, null, message.getBytes());
            System.err.println("发送消息完毕" + message);
        }
    }
}
